<?php
/**
 * Created by PhpStorm.
 * Script Name: EventMessageHandler.php
 * Create: 2020/4/15 10:48
 * Description: 公众号事件消息处理器
 * @link https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html  微信官方文档
 * Author: fudaoji<fdj@kuryun.cn>
 */
namespace plugin\wechat\app\platform\handler\mp;


use app\common\service\Queue;
use EasyWeChat\Kernel\Messages\Image;
use EasyWeChat\Kernel\Messages\Text;
use plugin\wechat\app\model\MpFollow;
use plugin\wechat\app\model\MpRule;
use plugin\wechat\app\model\MpSpecial;
use plugin\wechat\app\model\MpQrcode;
use plugin\wechat\app\model\MpQrcodeLog;
use plugin\wechat\app\model\MiniTemplateLog;
use plugin\wechat\app\service\Mp as MpService;
use plugin\wechat\app\service\Mini as MiniService;

class EventMessageHandler extends MessageHandler
{
    /**
     * @var MpFollow
     */
    private $followM;
    /**
     * @var MpSpecial
     */
    private $specialM;
    /**
     * @var MpRule
     */
    private $ruleM;
    /**
     * @var MiniTemplateLog
     */
    private $templateLogM;

    /**
     * 初始化
     * @author fudaoji<fdj@kuryun.cn>
     */
    public function __construct() {
        parent::__construct();
        $this->specialM = new MpSpecial();
        $this->ruleM = new MpRule();
        $this->followM = new MpFollow();
        $this->templateLogM = new MiniTemplateLog();
    }

    /**
     * 处理器
     * @param null $payload
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @author fudaoji<fdj@kuryun.cn>
     */
    public function handle($payload = null) {
        parent::handle($payload);
        $method = camel_case('event_' . $payload['Event']);
        if(method_exists($this, $method)) {
            return call_user_func_array([$this, $method], [$payload]);
        }
        dao_log()->error('无此事件处理方法:' . $method);
    }

    /**
     * 链接点击
     * @return Text
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function eventVIEW(){
        return new Text("success");
    }

    /**
     * 模板消息发送成功后的通知回调
     * @param $event
     * link: https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Template_Message_Interface.html#6
     * Author: fudaoji<fdj@kuryun.cn>
     * @return Text
     */
    public function eventTEMPLATESENDJOBFINISH($event){
        return new Text("success");
    }

    /**
     * 用户订阅消息事件
     * @param $event
     * link https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/subscribe-message.html
     * Author: fudaoji<fdj@kuryun.cn>
     * @return Text
     */
    public function eventSubscribeMsgSentEvent($event){
        //Log::error('小程序订阅消息事件：' . var_export($event, true));
        return new Text("success");
    }

    /**
     * 关注事件
     * @param $event
     * @return bool|mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @author: fudaoji<fdj@kuryun.cn>
     */
    public function eventSubscribe($event) {
        $request = request();
        $mp_info = $request->mpInfo;
        $app = $request->mpApp;
        $follow = $request->followInfo;

        if($follow && empty($follow['subscribe'])){
            $this->followM->update(
                ['subscribe' => 1, 'subscribe_time' => time()],
                ['company_id' =>  $mp_info['company_id'], 'openid' => $follow['openid']]
            );
            $follow['subscribe'] = 1;
            $follow['subscribe_time'] = time();
            $request->followInfo = $follow;
        }

        //扫描带参数二维码事件
        if($event['Event'] !== 'subscribe' && !empty($event['EventKey']) && strpos($event['EventKey'], 'qrscene_') !== false) {
            //todo 根据生成二维码创建的规则处理对应事件
            return $this->eventSCAN($event);
        }

        //执行关注时回复
        $res = $this->replySpecial(MpService::EVENT_SUBSCRIBE, $event);

        if(config('app.debug')){
            //$res = $this->testSubscribe($event);
        }

        if($res){
            return $res;
        }
    }

    /**
     * 取消订阅
     * @param $event
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @author fudaoji<fdj@kuryun.cn>
     */
    public function eventUnsubscribe($event) {
        $request = request();
        $mp_info = $request->mpInfo;
        $follow = $this->followM->where([
            ['openid', '=', $event['FromUserName']],
            ['mp_id', '=', $mp_info['id']],
            ['company_id', '=', $mp_info['company_id']]
        ])->find();
        if($follow){
            $this->followM->update([
                'id' => $follow['id'],
                'company_id' => $mp_info['company_id'],
                'subscribe' => 0,
                'unsubscribe_time' => time()
            ]);
        }

        $this->replySpecial(MpService::EVENT_UNSUBSCRIBE, $event);
    }

    /**
     * 扫描带参二维码事件
     * @param $event
     * @return bool|mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @author: fudaoji<fdj@kuryun.cn>
     */
    public function eventSCAN($event) {
        $mp_info = request()->mpInfo;
        $qr = MpQrcode::where([
            ['company_id' ,'=', $mp_info['company_id']],
            ['mp_id','=', $mp_info['id']],
            ['ticket','=', $event['Ticket']],
        ])->find();

        if(empty($qr)){
            return false;
        }
        if($qr['type'] == 1 && strtotime($qr['create_time']) + $qr['expire'] < time()){
            return new Text('二维码已失效');
        }
        //统计二维码
        try {
            $qr_update = [
                'id' => $qr['id'],
                'scan_num' => $qr['scan_num'] + 1
            ];
            $event['Event'] == 'subscribe' && $qr_update['gz_num'] = $qr['gz_num'] + 1;
            MpQrcode::update($qr_update);

            $log = MpQrcodeLog::where([
                ['company_id' ,'=', $mp_info['company_id']],
                ['mp_id','=', $mp_info['id']],
                ['qrcode_id','=', $qr['id']],
                ['openid' ,'=', $event['FromUserName']]
            ])->find();
            if($log){
                MpQrcodeLog::update([
                    'id' => $log['id'],
                    'company_id' => $mp_info['company_id'],
                    'mp_id' => $mp_info['id'],
                    'scan_num' => $log['scan_num'] + 1
                ]);
            }else{
                MpQrcodeLog::create([
                    'qrcode_id' => $qr['id'],
                    'company_id' => $mp_info['company_id'],
                    'mp_id' => $mp_info['id'],
                    'openid' => $event['FromUserName'],
                    'ticket' => $qr['ticket'],
                    'type' => $event['Event'] == 'SCAN' ? 0 : 1
                ]);
            }
        }catch (\Exception $e){
            dao_log()->error(json_encode($e->getMessage(), JSON_UNESCAPED_UNICODE));
        }

        return $event['event'] == 'subscribe' ? $this->replySpecial(MpService::EVENT_SUBSCRIBE, $event)
            : $this->replyKeyword($qr['keyword'], $event);
    }

    /**
     * 上报位置消息
     * @param $event
     * @return bool|mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @author: fudaoji<fdj@kuryun.cn>
     */
    public function eventLocation($event) {
        $res = $this->replySpecial(MpService::EVENT_LOCATION, $event);
        if($res){
            return $res;
        }
    }

    /**
     * 自定义菜单拉取消息事件
     * @param $event
     * @return bool|mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * @author: fudaoji<fdj@kuryun.cn>
     */
    public function eventClick($event) {
        $res = $this->replyKeyword($event['EventKey'], $event);
        if($res){
            return $res;
        }
    }

    /**
     * 小程序审核通过事件
     * @param $event
     * @return Text
     * @throws \think\db\exception\DbException
     * @link https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/code/audit_event.html
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function eventWeappAuditSuccess($event){
        var_dump($event);
        $this->templateLogM->where([
            ['mini_id', '=', request()->mpInfo['id']],
            ['status', '=', MiniService::STATUS_VERIFYING]
        ])
            ->update(['status' => MiniService::STATUS_SUCCESS]);
        return new Text("success");
    }

    /**
     * 小程序审核不通过事件
     * @param $event
     * @return Text
     * @throws \think\db\exception\DbException
     * @link https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/code/audit_event.html
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function eventWeappAuditFail($event){
        $this->templateLogM->where([
            ['mini_id', '=', request()->mpInfo['id']],
            ['status', '=', MiniService::STATUS_VERIFYING]
        ])
            ->update(['reason' => $event['Reason'], 'status' => MiniService::STATUS_FAIL]);
        return new Text("success");
    }

    /**
     * 小程序审核延后事件
     * @param $event
     * @return Text
     * @throws \think\db\exception\DbException
     * @link https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/code/audit_event.html
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function eventWeappAuditDelay($event){
        $this->templateLogM->where([
            ['mini_id', '=', request()->mpInfo['id']],
            ['status', '=', MiniService::STATUS_VERIFYING]
        ])
            ->update(['reason' => $event['Reason'], 'status' => MiniService::STATUS_DELAY]);
        return new Text("success");
    }

    //关注测试
    private function testSubscribe($event)
    {
        if(request()->mpInfo['appid'] == 'wx10ddcef6537dd78c'){
            //==========test=======================
            $this->replyCustomerService(new Text("第一条"), $event['FromUserName']);
            //$this->replyCustomerService(new Image("JW8XS34h_ISSqHFm_g1WsbEM_s4nroZEuR2XzJZODQN2tqN6NiOkDnVUwEAeYUx8"), $event['FromUserName']);
            Queue::push([
                'consumer' => ['\\plugin\\wechat\\app\\queue\\Mp', 'customerServiceSend'],
                'mp_info' => \request()->mpInfo,
                'content' => "JW8XS34h_ISSqHFm_g1WsbEM_s4nroZEuR2XzJZODQN2tqN6NiOkDnVUwEAeYUx8",
                "to" => $event['FromUserName'],
                'delay' => 40
            ]);
            return new Image("JW8XS34h_ISSqHFm_g1WsbEM_s4nroZEuR2XzJZODQN2tqN6NiOkDnVUwEAeYUx8");
            //==========test end=======================
        }
    }

    /**
     * 支付成功
     * @return Text
     * Author: fudaoji<fdj@kuryun.cn>
     */
    function eventWxVerifyPaySucc(){
        return new Text("success");
    }
    function eventWxVerifyDispatch(){
        return new Text("success");
    }

    /**
     * 资质认证成功提醒
     * @return Text
     * Author: fudaoji<fdj@kuryun.cn>
     */
    function eventQualificationVerifySuccess(){
        return new Text("success");
    }

    /**
     * 实名认证成功
     * @return Text
     * Author: fudaoji<fdj@kuryun.cn>
     */
    function eventNamingVerifySuccess(){
        return new Text("success");
    }

    function eventMASSSENDJOBFINISH(){
        return new Text("success");
    }

    function eventUserAuthorizationCancellation(){
        return new Text("success");
    }
}